#include<stdio.h>
#include<cstring>
#include<Windows.h>
using namespace std;


char dllPath[MAX_PATH] = "E:\\工程文件\\EntryPointDemo\\Debug\\Dll1.dll";
const char exePath[MAX_PATH] = "C:\\Users\\Administrator\\Desktop\\game.exe";

typedef HMODULE(*_loadLibrayA)(LPCSTR);
typedef HMODULE (*_getModuleHandle)(LPCSTR);
typedef BOOL (*_virtualProtect)(LPVOID ,SIZE_T,DWORD,PDWORD);

typedef struct ROMOTE_DATA
{
	char path[MAX_PATH];//dll地址
	_loadLibrayA loadLibrary;
	DWORD entryPoint;
	_getModuleHandle getModuleHande;
	_virtualProtect  virtualProtect;
	char code[0x5];
	LPVOID injectAddr;

}*PROMOTE_DATA;

PROMOTE_DATA rotData;

DWORD GetEntryPointAddr();
void initRotData()
{
	//strcpy_s(rotData->path,dllPath);
	// dllpath -> ROMOTE_DATA
	memcpy(rotData->path,dllPath,sizeof(dllPath));
   // get Kernel32
	HMODULE hMod =  LoadLibraryA("Kernel32.dll");
	// load -> ROMOTE_DATA.loadLo
	rotData->loadLibrary = (_loadLibrayA)GetProcAddress(hMod, "LoadLibraryA");
	//printf("loadLibrary :%x\n", rotData->loadLibrary);
	rotData->entryPoint = GetEntryPointAddr();

	rotData->getModuleHande = (_getModuleHandle)GetProcAddress(hMod, "GetModuleHandleA");
	//printf("getModuleHande:%x\n", rotData->getModuleHande);
	rotData->virtualProtect = (_virtualProtect)GetProcAddress(hMod, "VirtualProtect");
	//printf("virtualProtect: %x\n", rotData->virtualProtect);

}

// 获取入口地址
DWORD GetEntryPointAddr()
{
	HANDLE hFile = CreateFileA(exePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	int szFile = GetFileSize(hFile, NULL);
	LPBYTE lpFile = new BYTE[szFile];
	int ret = ReadFile(hFile, lpFile, szFile, NULL, NULL);
	if (ret == 0)
	{
		printf("read file error:%d", GetLastError());
		return NULL;
	}

	PIMAGE_DOS_HEADER imgDosHeader = (PIMAGE_DOS_HEADER)lpFile;
	PIMAGE_NT_HEADERS imgNtHeader = (PIMAGE_NT_HEADERS)(lpFile + imgDosHeader->e_lfanew);
	PIMAGE_OPTIONAL_HEADER imgOptionHeader = &(imgNtHeader->OptionalHeader);

	DWORD bRet = imgOptionHeader->AddressOfEntryPoint;

	if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
	if (lpFile != NULL) delete[] lpFile;

	return bRet;
}

void InjectFunc()
{
	PROMOTE_DATA pData = (PROMOTE_DATA)0xCCCCCCCC;
	pData->loadLibrary(pData->path);

	char* prevcode = (char*)pData->entryPoint;
	for (int i = 0; i < 0x5; i++) prevcode[i] = pData->code[i];

	unsigned point = pData->entryPoint;
	__asm
	{
		mov eax, point
		jmp eax
	}
}

void modifyEntryPoint(PROMOTE_DATA p)
{
	DWORD baseAddr= (DWORD)p->getModuleHande(0);
	p->entryPoint += baseAddr;

	DWORD lwt{};
	p->virtualProtect((LPVOID)p->entryPoint, 0x5, PAGE_EXECUTE_READWRITE, &lwt);

	char *prevcode = (char*)p->entryPoint;
	for (int i = 0; i < 5; ++i) p->code[i] = prevcode[i];
	prevcode[0] = 0xE9;//jmp
	unsigned distance = (unsigned)( (DWORD)p->injectAddr - p->entryPoint - 0x5);

	unsigned *_code = (unsigned*)(p->entryPoint+1);
	_code[0] = distance;

}
int main()
{
	STARTUPINFOA startUp;
	ZeroMemory(&startUp, sizeof(STARTUPINFOA));
	PROCESS_INFORMATION  proInfo;
	ZeroMemory(&proInfo, sizeof(PROCESS_INFORMATION));
	int bRet = CreateProcessA(exePath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL,
		"C:\\Users\\Administrator\\Desktop\\",
		&startUp, &proInfo);
	if (bRet == 0)
	{
		printf("createprocess error:%d\n", GetLastError());
		return 0;
	}

	//进行入口点注入
	rotData = new ROMOTE_DATA;

	DWORD rotAddr=(DWORD)VirtualAllocEx(proInfo.hProcess, NULL, 0x3000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	DWORD rotDataAddr = rotAddr + 0x200;
	
	initRotData();

	char modifyCode[0x200];
		
	memcpy(modifyCode, InjectFunc, sizeof(modifyCode));

	for (int i = 0; i < 0x200; i++)
	{ 
		unsigned* pcode = (unsigned*)(&modifyCode[i]);
		if(pcode[0] == 0xCCCCCCCC)
		{
			pcode[0] = (unsigned)rotDataAddr;
			break;
		}
	}

	DWORD injectAddr = rotAddr + 0x1000; //注入dll的函数
	rotData->injectAddr = (LPVOID)injectAddr;
	WriteProcessMemory(proInfo.hProcess, (LPVOID)rotDataAddr, rotData, 0x200, NULL);

	WriteProcessMemory(proInfo.hProcess, (LPVOID)injectAddr, modifyCode, 0x200, NULL);

	DWORD rotFuncAddr = rotAddr + 0x2000; //写入远程函数
	WriteProcessMemory(proInfo.hProcess, (LPVOID)rotFuncAddr, modifyEntryPoint, 0x500, NULL);

	HANDLE hProcHnd = CreateRemoteThread(proInfo.hProcess, NULL, 0,
		(LPTHREAD_START_ROUTINE)rotFuncAddr, (LPVOID)rotDataAddr, 0, NULL);
	if (hProcHnd != INVALID_HANDLE_VALUE) WaitForSingleObject(hProcHnd, INFINITE);
	else printf("CreateRemoteThread error : %d", GetLastError());

	//注入完成后恢复进程运行
	ResumeThread(proInfo.hThread);


	
	return 0;
}
